#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#include "os_api.h"
#include "atclient.h"
#include "lpconfig.h"


extern void lp_cmd_start(void);
extern void lp_cmd_stop(void);
extern void lp_cmd_wakeup(void);
extern void lp_cmd_sleep(void);


#define MAT_CMD_TYPE_MIN	_MAT_MIN

#define MAT_plusTESTVALUE	MAT_CMD_TYPE_MIN+1
#define MAT_plusTESTSTRING	MAT_CMD_TYPE_MIN+2

#define MAT_CMD_TYPE_MAX	_MAT_MAX


static utlAtParameter_T one_decimal_params[] = { 
	utlDEFINE_DECIMAL_AT_PARAMETER( utlAT_PARAMETER_ACCESS_READ_WRITE, utlAT_PARAMETER_PRESENCE_OPTIONAL)
	};

static utlAtParameter_T one_string_params[] = {
	utlDEFINE_STRING_AT_PARAMETER( utlAT_PARAMETER_ACCESS_READ_WRITE, utlAT_PARAMETER_PRESENCE_OPTIONAL),
	};

static utlAtParameter_T five_string_params[] = {
    utlDEFINE_STRING_AT_PARAMETER(utlAT_PARAMETER_ACCESS_READ_WRITE, utlAT_PARAMETER_PRESENCE_OPTIONAL),
	utlDEFINE_STRING_AT_PARAMETER( utlAT_PARAMETER_ACCESS_READ_WRITE, utlAT_PARAMETER_PRESENCE_OPTIONAL),
	utlDEFINE_STRING_AT_PARAMETER( utlAT_PARAMETER_ACCESS_READ_WRITE, utlAT_PARAMETER_PRESENCE_OPTIONAL),
	utlDEFINE_STRING_AT_PARAMETER( utlAT_PARAMETER_ACCESS_READ_WRITE, utlAT_PARAMETER_PRESENCE_OPTIONAL),
	utlDEFINE_STRING_AT_PARAMETER( utlAT_PARAMETER_ACCESS_READ_WRITE, utlAT_PARAMETER_PRESENCE_OPTIONAL),
	};

static lpSetCfg curLpCfgInfo = {0};

lpSetCfg * getLpCfgInfo(void)
{
    return &curLpCfgInfo;
}

static lpWakeupReason curWakeupReason = LP_WAKEUP_NONE;

lpWakeupReason getWakeupReason(void)
{
	return curWakeupReason;
}

void setWakeupReason(lpWakeupReason value)
{
	curWakeupReason = value;
}

RETURNCODE_T  AtLPCFG(            const utlAtParameterOp_T        op,
		const char                      *command_name_p,
		const utlAtParameterValue_P2c   parameter_values_p,
		const size_t                    num_parameters,
		const char                      *info_text_p,
		unsigned int                    *xid_p,
		void                            *arg_p)
{
	UINT32 sAtpIndex = * (UINT32 *) arg_p;
	UINT32 atHandle = atcmds_make_at_handle( sAtpIndex );
	RETURNCODE_T ret = utlSUCCESS;

    char buf[64+1]={0};
    INT16 buf_len =0;

	char buf1[64+1]={0};
	INT16 buf1_len =0;	

	char buf2[64+1]={0};
	INT16 buf2_len =0;
	
	char buf3[64+1]={0};
	INT16 buf3_len =0;

	char buf4[64+1]={0};
	INT16 buf4_len =0;

    lpSetCfg *cfg = getLpCfgInfo();

    UINT8   type = 0;
    INT32   value1 = 0;
    INT32   value2 = 0;
    INT32   value3 = 0;
    INT32   value4 = 0;
									
	*xid_p = atHandle;
	
	switch(op)
	{
		case TEL_EXT_GET_CMD:
            ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);

			break;

		case TEL_EXT_SET_CMD:

			if( getExtString( parameter_values_p, 0, buf, 64, &buf_len, NULL ) == FALSE )
			{
				ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
				break;
			}

            if(strncasecmp((char *)buf, "method", strlen("method")) == 0)
			{
				if (parameter_values_p[1].is_default){
					
					buf_len = snprintf(buf, 64, "+LPCFG: \"method\",%d\r\n", cfg->method);

					ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, buf);
				    break;
				}

				if( getExtString( parameter_values_p, 1, buf1, 64, &buf1_len, NULL ) == FALSE )
				{
					ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
					break;
				}
				value1 = atoi(buf1);

				if (value1 < 0 || value1 > 1){
					ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
					break;						
				}
				cfg->method = value1;
				
				ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);
				break;
            }
			else if(strncasecmp((char *)buf, "host", strlen("host")) == 0)
			{
				if (parameter_values_p[1].is_default){
					
					buf_len = snprintf(buf, 64, "+LPCFG: \"host\",\"%s\",%d\r\n", cfg->hostname, cfg->port);

					ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, buf);
				    break;
				}

				if( getExtString( parameter_values_p, 1, cfg->hostname, sizeof(cfg->hostname)-1, &buf1_len, NULL ) == FALSE )
				{
					ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
					break;
				}				

				if( getExtString( parameter_values_p, 2, buf2, 64, &buf2_len, NULL ) == FALSE )
				{
					ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
					break;
				}
				value2 = atoi(buf2);

				if (value2 < 0 || value2 > 65535){
					ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
					break;						
				}
				cfg->port = value2;
				ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);
				break;
            }			
			else if(strncasecmp((char *)buf, "mqtt/clientid", strlen("mqtt/clientid")) == 0)
			{
				if (parameter_values_p[1].is_default){
					
					buf_len = snprintf(buf, 64, "+LPCFG: \"mqtt/clientid\",\"%s\"\r\n", cfg->mqtt_clientid);

					ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, buf);
				    break;
				}

				if( getExtString( parameter_values_p, 1, cfg->mqtt_clientid, sizeof(cfg->mqtt_clientid)-1, &buf1_len, NULL ) == FALSE )
				{
					ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
					break;
				}				
				
				ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);
				break;
            }
			else if(strncasecmp((char *)buf, "mqtt/username", strlen("mqtt/username")) == 0)
			{
				if (parameter_values_p[1].is_default){
					
					buf_len = snprintf(buf, 64, "+LPCFG: \"mqtt/username\",\"%s\"\r\n", cfg->mqtt_username);

					ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, buf);
				    break;
				}

				if( getExtString( parameter_values_p, 1, cfg->mqtt_username, sizeof(cfg->mqtt_username)-1, &buf1_len, NULL ) == FALSE )
				{
					ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
					break;
				}				
				
				ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);
				break;
            }		
			else if(strncasecmp((char *)buf, "mqtt/password", strlen("mqtt/password")) == 0)
			{
				if (parameter_values_p[1].is_default){
					
					buf_len = snprintf(buf, 64, "+LPCFG: \"mqtt/password\",\"%s\"\r\n", cfg->mqtt_password);

					ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, buf);
				    break;
				}

				if( getExtString( parameter_values_p, 1, cfg->mqtt_password, sizeof(cfg->mqtt_password)-1, &buf1_len, NULL ) == FALSE )
				{
					ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
					break;
				}				
				
				ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);
				break;
            }
			else if(strncasecmp((char *)buf, "tcp/heart", strlen("tcp/heart")) == 0)
			{
				if (parameter_values_p[1].is_default){
					
					buf_len = snprintf(buf, 64, "+LPCFG: \"tcp/heart\",\"%s\",\"%s\",%d,%d\r\n", cfg->tcp_heart, cfg->tcp_heart_resp, cfg->tcp_heart_interval, cfg->tcp_heart_miss_max);

					ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, buf);
				    break;
				}

				if( getExtString( parameter_values_p, 1, cfg->tcp_heart, sizeof(cfg->tcp_heart)-1, &buf1_len, NULL ) == FALSE )
				{
					ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
					break;
				}				

				if( getExtString( parameter_values_p, 2, cfg->tcp_heart_resp, sizeof(cfg->tcp_heart_resp)-1, &buf2_len, NULL ) == FALSE )
				{
					ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
					break;
				}			

				if( getExtString( parameter_values_p, 3, buf3, 64, &buf3_len, NULL ) == FALSE )
				{
					ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
					break;
				}
				value3 = atoi(buf3);

				if (value3 < 0 || value3 > 1000){
					ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
					break;						
				}
				cfg->tcp_heart_interval = value3;

				if( getExtString( parameter_values_p, 4, buf4, 64, &buf4_len, NULL ) == FALSE )
				{
					ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
					break;
				}
				value4 = atoi(buf4);

				if (value4 < 0 || value4 > 10){
					ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
					break;						
				}
				cfg->tcp_heart_miss_max = value4;

				ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);
				break;
            }			
			else if(strncasecmp((char *)buf, "tcp/wakeup", strlen("tcp/wakeup")) == 0)
			{
				if (parameter_values_p[1].is_default){
					
					buf_len = snprintf(buf, 64, "+LPCFG: \"tcp/wakeup\",\"%s\"\r\n", cfg->tcp_wakeup);

					ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, buf);
				    break;
				}

				if( getExtString( parameter_values_p, 1, cfg->tcp_wakeup, sizeof(cfg->tcp_wakeup)-1, &buf1_len, NULL ) == FALSE )
				{
					ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
					break;
				}

				ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);
				break;
            }
			else
			{
            
    		}
			break;

		case TEL_EXT_TEST_CMD:
		    
            ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);
			break;

		default:
			ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
			break;
	}
	return ret;
}


RETURNCODE_T  AtLPSTART(            const utlAtParameterOp_T        op,
		const char                      *command_name_p,
		const utlAtParameterValue_P2c   parameter_values_p,
		const size_t                    num_parameters,
		const char                      *info_text_p,
		unsigned int                    *xid_p,
		void                            *arg_p)
{
	UINT32 sAtpIndex = * (UINT32 *) arg_p;
	UINT32 atHandle = atcmds_make_at_handle( sAtpIndex );
	RETURNCODE_T ret = utlSUCCESS;
	
	static int Value = 0;	

	char buf[32] = {0};
	
	printf("%s: atHandle = %ld, sAtpIndex = %ld.\n", __FUNCTION__, atHandle, sAtpIndex);

	*xid_p = atHandle;
	switch(op)
	{	
		case TEL_EXT_ACTION_CMD:
			lp_cmd_start();
			ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);	
			break;
		case TEL_EXT_SET_CMD:
			break;			
		case TEL_EXT_GET_CMD:
            ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);	
			break;
		case TEL_EXT_TEST_CMD:
			ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);						
			break;

		default:
			ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
			break;
	}
	
	return ret;
}


RETURNCODE_T  AtLPSTOP(            const utlAtParameterOp_T        op,
		const char                      *command_name_p,
		const utlAtParameterValue_P2c   parameter_values_p,
		const size_t                    num_parameters,
		const char                      *info_text_p,
		unsigned int                    *xid_p,
		void                            *arg_p)
{
	UINT32 sAtpIndex = * (UINT32 *) arg_p;
	UINT32 atHandle = atcmds_make_at_handle( sAtpIndex );
	RETURNCODE_T ret = utlSUCCESS;
	
	static int Value = 0;	

	char buf[32] = {0};
	
	printf("%s: atHandle = %ld, sAtpIndex = %ld.\n", __FUNCTION__, atHandle, sAtpIndex);

	*xid_p = atHandle;
	switch(op)
	{	
		case TEL_EXT_ACTION_CMD:
			lp_cmd_stop();
			ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);	
			break;
		case TEL_EXT_SET_CMD:
			break;			
		case TEL_EXT_GET_CMD:
            ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);	
			break;
		case TEL_EXT_TEST_CMD:
			ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);						
			break;

		default:
			ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
			break;
	}
	
	return ret;
}

RETURNCODE_T  AtLPSLEEP(            const utlAtParameterOp_T        op,
		const char                      *command_name_p,
		const utlAtParameterValue_P2c   parameter_values_p,
		const size_t                    num_parameters,
		const char                      *info_text_p,
		unsigned int                    *xid_p,
		void                            *arg_p)
{
	UINT32 sAtpIndex = * (UINT32 *) arg_p;
	UINT32 atHandle = atcmds_make_at_handle( sAtpIndex );
	RETURNCODE_T ret = utlSUCCESS;
	
	static int Value = 0;	

	char buf[32] = {0};
	
	printf("%s: atHandle = %ld, sAtpIndex = %ld.\n", __FUNCTION__, atHandle, sAtpIndex);

	*xid_p = atHandle;
	switch(op)
	{	
		case TEL_EXT_ACTION_CMD:
			lp_cmd_sleep();
			ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);	
			break;
		case TEL_EXT_SET_CMD:
			break;			
		case TEL_EXT_GET_CMD:
            ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);	
			break;
		case TEL_EXT_TEST_CMD:
			ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);						
			break;

		default:
			ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
			break;
	}
	
	return ret;
}

RETURNCODE_T  AtLPWAKEUP(            const utlAtParameterOp_T        op,
		const char                      *command_name_p,
		const utlAtParameterValue_P2c   parameter_values_p,
		const size_t                    num_parameters,
		const char                      *info_text_p,
		unsigned int                    *xid_p,
		void                            *arg_p)
{
	UINT32 sAtpIndex = * (UINT32 *) arg_p;
	UINT32 atHandle = atcmds_make_at_handle( sAtpIndex );
	RETURNCODE_T ret = utlSUCCESS;
	
	static int Value = 0;	

	char buf[32] = {0};
	
	printf("%s: atHandle = %ld, sAtpIndex = %ld.\n", __FUNCTION__, atHandle, sAtpIndex);

	*xid_p = atHandle;
	switch(op)
	{	
		case TEL_EXT_ACTION_CMD:
			lp_cmd_wakeup();
			ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);	
			break;
		case TEL_EXT_SET_CMD:
			break;			
		case TEL_EXT_GET_CMD:
            ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);	
			break;
		case TEL_EXT_TEST_CMD:
			ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);						
			break;

		default:
			ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
			break;
	}
	
	return ret;
}


RETURNCODE_T  AtLPRDWREASON(            const utlAtParameterOp_T        op,
		const char                      *command_name_p,
		const utlAtParameterValue_P2c   parameter_values_p,
		const size_t                    num_parameters,
		const char                      *info_text_p,
		unsigned int                    *xid_p,
		void                            *arg_p)
{
	UINT32 sAtpIndex = * (UINT32 *) arg_p;
	UINT32 atHandle = atcmds_make_at_handle( sAtpIndex );
	RETURNCODE_T ret = utlSUCCESS;
	
	static int Value = 0;	

	char buf[32] = {0};
	
	printf("%s: atHandle = %ld, sAtpIndex = %ld.\n", __FUNCTION__, atHandle, sAtpIndex);

	*xid_p = atHandle;
	switch(op)
	{	
		case TEL_EXT_ACTION_CMD:
			ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);	
			break;
		case TEL_EXT_SET_CMD:
			ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);	
			break;			
		case TEL_EXT_GET_CMD:
			sprintf(buf, "+LPRDWREASON: %d", getWakeupReason());
            ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);	
			break;
		case TEL_EXT_TEST_CMD:
			ret = ATRESP(atHandle, ATCI_RESULT_CODE_OK, 0, NULL);						
			break;

		default:
			ret = ATRESP(atHandle, ATCI_RESULT_CODE_ERROR, 0, NULL);
			break;
	}
	
	return ret;
}

static utlAtCommand_T ext_at_commands[] = {
	utlDEFINE_EXTENDED_EXACTION_VSYNTAX_AT_COMMAND(MAT_plusTESTVALUE, "+LPCFG", five_string_params, AtLPCFG, AtLPCFG, AtLPCFG),
	utlDEFINE_EXTENDED_EXACTION_VSYNTAX_AT_COMMAND(MAT_plusTESTVALUE, "+LPSTART", one_decimal_params, AtLPSTART, AtLPSTART, AtLPSTART),
	utlDEFINE_EXTENDED_EXACTION_VSYNTAX_AT_COMMAND(MAT_plusTESTVALUE, "+LPSTOP", one_decimal_params, AtLPSTOP, AtLPSTOP, AtLPSTOP),
	utlDEFINE_EXTENDED_EXACTION_VSYNTAX_AT_COMMAND(MAT_plusTESTVALUE, "+LPSLEEP", one_decimal_params, AtLPSLEEP, AtLPSLEEP, AtLPSLEEP),
	utlDEFINE_EXTENDED_EXACTION_VSYNTAX_AT_COMMAND(MAT_plusTESTVALUE, "+LPWAKEUP", one_decimal_params, AtLPWAKEUP, AtLPWAKEUP, AtLPWAKEUP),
	utlDEFINE_EXTENDED_EXACTION_VSYNTAX_AT_COMMAND(MAT_plusTESTVALUE, "+LPRDWREASON", one_decimal_params, AtLPRDWREASON, AtLPRDWREASON, AtLPRDWREASON),	
};

#define utlNumberOf(n) (sizeof(n) / sizeof((n)[0]))

unsigned int ext_at_commands_num = utlNumberOf(ext_at_commands);

void atcmds_register_init(void)
{
    int i;
    for (i = 0; i < ext_at_commands_num; i++){
        printf("register atcmd: %s, sizeof: %d\r\n", ext_at_commands[i].name_p, sizeof(utlAtCommand_T));
    }    

    atcmds_register(ext_at_commands, ext_at_commands_num);
}
